Cadences#

import os
from collections import defaultdict, Counter

from git import Repo
import dimcat as dc
import ms3
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

from utils import STD_LAYOUT, CADENCE_COLORS, color_background, value_count_df
CORPUS_PATH = os.environ.get('CORPUS_PATH', "~/dcml_corpora")
CORPUS_PATH
'~/dcml_corpora'
repo = Repo(CORPUS_PATH)
notebook_repo = Repo('.', search_parent_directories=True)
notebook_repo_path = notebook_repo.git.rev_parse("--show-toplevel")
print(f"Notebook repository '{os.path.basename(notebook_repo_path)}' @ {notebook_repo.commit().hexsha[:7]}")
print(f"Data repo '{os.path.basename(CORPUS_PATH)}' @ {repo.commit().hexsha[:7]}")
print(f"dimcat version {dc.__version__}")
print(f"ms3 version {ms3.__version__}")
Notebook repository 'notebooks' @ f478afd
Data repo 'dcml_corpora' @ 3612b3b
dimcat version 0.3.0
ms3 version 1.2.4

Data loading#

dataset = dc.Dataset()
for folder in ['corelli', 'liszt_pelerinage']:
    print("Loading", folder)
    path = os.path.join(CORPUS_PATH, folder)
    dataset.load(directory=path)
dataset.data
Loading corelli
Loading liszt_pelerinage
[default|all]
All corpora
-----------
View: This view is called 'default'. It
	- excludes fnames that are not contained in the metadata,
	- filters out file extensions requiring conversion (such as .xml), and
	- excludes review files and folders.

                      has   active   scores measures           notes        expanded
                 metadata     view detected detected parsed detected parsed detected parsed
corpus
corelli               yes  default      149      149    149      149    149      149    149
liszt_pelerinage      yes  default       19       19     19       19     19       19     19

1191/3375 files are excluded from this view.

1176 files have been excluded based on their subdir.
15 files have been excluded based on their file name.

Filtering out pieces without cadence annotations#

hascadence = dc.HasCadenceAnnotationsFilter().process_data(dataset)
print(f"Before: {len(dataset.indices[()])} pieces; after removing those without cadence labels: {len(hascadence.indices[()])}")
Before: 168 pieces; after removing those without cadence labels: 167

Show corpora containing pieces with cadence annotations#

grouped_by_dataset = dc.CorpusGrouper().process_data(hascadence)
corpora = {group[0]: f"{len(ixs)} pieces" for group, ixs in  grouped_by_dataset.indices.items()}
print(f"{len(corpora)} corpora with {sum(map(len, grouped_by_dataset.indices.values()))} pieces containing cadence annotations:")
corpora
2 corpora with 167 pieces containing cadence annotations:
{'corelli': '148 pieces', 'liszt_pelerinage': '19 pieces'}

All annotation labels from the selected pieces#

all_labels = hascadence.get_facet('expanded')

print(f"{len(all_labels.index)} hand-annotated harmony labels:")
all_labels.iloc[:10, 14:].style.apply(color_background, subset="chord")
19374 hand-annotated harmony labels:
      chord numeral form figbass changes relativeroot cadence phraseend chord_type globalkey_is_minor localkey_is_minor chord_tones added_tones root bass_note placement special pedalend
corpus fname interval                                    
corelli op01n01a [0.0, 1.0) I I nan nan nan nan nan { M False False (0, 4, 1) () 0 0 nan nan nan
[1.0, 2.0) viio6 vii o 6 nan nan nan nan o False False (2, -1, 5) () 5 2 nan nan nan
[2.0, 4.0) I6 I nan 6 nan nan nan nan M False False (4, 1, 0) () 0 4 nan nan nan
[4.0, 4.5) IV IV nan nan nan nan nan nan M False False (-1, 3, 0) () -1 -1 nan nan nan
[4.5, 5.0) I I nan nan nan nan nan nan M False False (0, 4, 1) () 0 0 nan nan nan
[5.0, 5.75) V(4) V nan nan 4 nan nan nan M False False (1, 0, 2) () 1 1 nan nan nan
[5.75, 6.0) V V nan nan nan nan nan nan M False False (1, 5, 2) () 1 1 nan nan nan
[6.0, 9.0) I I nan nan nan nan PAC } M False False (0, 4, 1) () 0 0 nan nan nan
[8.0, 8.0) nan nan nan nan nan nan nan { nan False False () () nan nan nan
[9.0, 9.5) I6 I nan 6 nan nan nan nan M False False (4, 1, 0) () 0 4 nan nan nan

Metadata#

dataset_metadata = hascadence.data.metadata()
hascadence_metadata = dataset_metadata.loc[hascadence.indices[()]]
hascadence_metadata.index.rename('dataset', level=0, inplace=True)
hascadence_metadata.head()
TimeSig KeySig last_mc last_mn length_qb last_mc_unfolded last_mn_unfolded length_qb_unfolded volta_mcs all_notes_qb ... staff_4_instrument score_integrity composed_source lyricist_text imslp musicbrainz viaf wikidata PDF typesetter
dataset fname
corelli op01n01a 1: 4/4 1: -1 14 14 56.0 14 14 56.0 NaN 224.00 ... Keyboard NaN NaN NaN NaN NaN NaN NaN NaN NaN
op01n01b 1: 4/4 1: -1 38 38 152.0 38 38 152.0 NaN 559.75 ... Keyboard NaN NaN NaN NaN NaN NaN NaN NaN NaN
op01n01c 1: 3/4 1: -1 37 37 111.0 37 37 111.0 NaN 430.00 ... Keyboard NaN NaN NaN NaN NaN NaN NaN NaN NaN
op01n01d 1: 3/4 1: -1 98 98 294.0 196 196 588.0 NaN 963.00 ... Keyboard NaN NaN NaN NaN NaN NaN NaN NaN NaN
op01n02a 1: 4/4 1: 1 19 19 76.0 19 19 76.0 NaN 288.00 ... Keyboard NaN NaN NaN NaN NaN NaN NaN NaN NaN

5 rows × 65 columns

mean_composition_years = hascadence_metadata.groupby(level=0).composed_end.mean().astype(int).sort_values()
chronological_order = mean_composition_years.index.to_list()
bar_data = pd.concat([mean_composition_years.rename('year'),
                      hascadence_metadata.groupby(level='dataset').size().rename('pieces')],
                     axis=1
                    ).reset_index()
fig = px.bar(bar_data, x='year', y='pieces', color='dataset', title='Pieces contained in the dataset')
fig.update_traces(width=5)

Overall#

  • PAC: Perfect Authentic Cadence

  • IAC: Imperfect Authentic Cadence

  • HC: Half Cadence

  • DC: Deceptive Cadence

  • EC: Evaded Cadence

  • PC: Plagal Cadence

print(f"{all_labels.cadence.notna().sum()} cadence labels.")
value_count_df(all_labels.cadence)
1333 cadence labels.
counts
cadence
PAC 791
HC 273
IAC 212
EC 35
PC 13
DC 9
px.pie(all_labels[all_labels.cadence.notna()], names="cadence", color="cadence", color_discrete_map=CADENCE_COLORS)

Per dataset#

cadence_count_per_dataset = all_labels.groupby("corpus").cadence.value_counts()
cadence_fraction_per_dataset = cadence_count_per_dataset / cadence_count_per_dataset.groupby(level=0).sum()
px.bar(cadence_fraction_per_dataset.rename('count').reset_index(), x='corpus', y='count', color='cadence',
      color_discrete_map=CADENCE_COLORS, category_orders=dict(dataset=chronological_order))
fig = px.pie(cadence_count_per_dataset.rename('count').reset_index(), names='cadence', color='cadence', values='count',
       facet_col='corpus', facet_col_wrap=4, height=2000, color_discrete_map=CADENCE_COLORS)
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_layout(**STD_LAYOUT)

Per phrase#

Number of cadences per phrase#

segmented = dc.PhraseSlicer().process_data(grouped_by_dataset)
phrases = segmented.get_slice_info()
phrase_segments = segmented.get_facet("expanded")
phrase_gpb = phrase_segments.groupby(level=[0,1,2])
local_keys_per_phrase = phrase_gpb.localkey.unique().map(tuple)
n_local_keys_per_phrase = local_keys_per_phrase.map(len)
phrases_with_keys = pd.concat([n_local_keys_per_phrase.rename('n_local_keys'),
                               local_keys_per_phrase.rename('local_keys'),
                               phrases], axis=1)
phrases_with_cadences = pd.concat([
    phrase_gpb.cadence.nunique().rename('n_cadences'),
    phrase_gpb.cadence.unique().rename('cadences').map(lambda l: tuple(e for e in l if not pd.isnull(e))),
    phrases_with_keys
], axis=1)
value_count_df(phrases_with_cadences.n_cadences, counts="#phrases")
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`

/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/dimcat/slicer.py:553: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
#phrases
n_cadences
1 1268
0 61
2 25
n_cad = phrases_with_cadences.groupby(level='corpus').n_cadences.value_counts().rename('counts').reset_index().sort_values('n_cadences')
n_cad.n_cadences = n_cad.n_cadences.astype(str)
fig = px.bar(n_cad, x='corpus', y='counts', color='n_cadences', height=800, barmode='group',
             labels=dict(n_cadences="#cadences in a phrase"),
             category_orders=dict(dataset=chronological_order)
      )
fig.show()

Combinations of cadence types for phrases with more than one cadence#

value_count_df(phrases_with_cadences[phrases_with_cadences.n_cadences > 1].cadences)
counts
cadences
(EC, PAC) 8
(EC, HC) 5
(DC, PAC) 4
(IAC, PAC) 2
(HC, PAC) 2
(DC, HC) 1
(PAC, IAC) 1
(HC, PC) 1
(EC, IAC) 1

Positioning of cadences within phrases#

df_rows = []
y_position = 0
for ix in phrases_with_cadences[phrases_with_cadences.n_cadences > 0].sort_values('duration_qb').index:
    df = phrase_segments.loc[ix]
    description = str(ix)
    if df.cadence.notna().any():
        interval = ix[2]
        df_rows.append((y_position, interval.length, "end of phrase", description))
        start_pos = interval.left
        cadences = df.loc[df.cadence.notna(), ['quarterbeats', 'cadence']]
        cadences.quarterbeats -= start_pos
        for cadence_x, cadence_type in cadences.itertuples(index=False, name=None):
            df_rows.append((y_position, cadence_x, cadence_type, description))
        y_position += 1
    #else:
    #    df_rows.append((y_position, pd.NA, pd.NA, description))

data = pd.DataFrame(df_rows, columns=["phrase_ix", "x", "marker", "description"])
fig = px.scatter(data[data.x.notna()], x='x', y="phrase_ix", color="marker", hover_name="description", height=3000,
                labels=dict(marker='legend'), color_discrete_map=CADENCE_COLORS)
fig.update_traces(marker_size=5)
fig.update_yaxes(autorange="reversed")
fig.show()

Cadence ultima#

phrase_segments = segmented.get_facet("expanded")
cadence_selector = phrase_segments.cadence.notna()
missing_chord_selector = phrase_segments.chord.isna()
cadence_with_missing_chord_selector = cadence_selector & missing_chord_selector
missing = phrase_segments[cadence_with_missing_chord_selector]
expanded = ms3.expand_dcml.expand_labels(phrase_segments[cadence_with_missing_chord_selector], propagate=False, chord_tones=True, skip_checks=True)
phrase_segments.loc[cadence_with_missing_chord_selector] = expanded
print(f"Ultima harmony missing for {(phrase_segments.cadence.notna() & phrase_segments.bass_note.isna()).sum()} cadence labels.")
/home/hentsche/miniconda3/envs/ms3/lib/python3.10/site-packages/ms3/expand_dcml.py:232: FutureWarning:

In a future version, `df.iloc[:, i] = newvals` will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either `df[df.columns[i]] = newvals` or, if columns are non-unique, `df.isetitem(i, newvals)`
Ultima harmony missing for 11 cadence labels.

Ultimae as Roman numeral#

def highlight(row, color="#ffffb3"):
    if row.counts < 10:
        return [None, None, None, None]
    else:
        return ["background-color: {color};"] * 4

cadence_counts = all_labels.cadence.value_counts()
ultima_root = phrase_segments.groupby(['localkey_is_minor', 'cadence']).numeral.value_counts().rename('counts').to_frame().reset_index()
ultima_root.localkey_is_minor = ultima_root.localkey_is_minor.map({False: 'in major', True: 'in minor'})
#ultima_root.style.apply(highlight, axis=1)
fig = px.pie(ultima_root, names='numeral', values='counts',
             facet_row='cadence', facet_col='localkey_is_minor',
             height=1500,
             category_orders={'cadence': cadence_counts.index},
            )
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_traces(textposition='inside', textinfo='percent+label')
fig.update_layout(**STD_LAYOUT)
fig.show()
#phrase_segments.groupby(level=[0,1,2], group_keys=False).apply(lambda df: df if ((df.cadence == 'PAC') & (df.numeral == 'V')).any() else None)

Ultimae bass note as scale degree#

ultima_bass = phrase_segments.groupby(['localkey_is_minor','cadence']).bass_note.value_counts().rename('counts').reset_index()
ultima_bass.bass_note = ms3.transform(ultima_bass, ms3.fifths2sd, dict(fifths='bass_note', minor='localkey_is_minor'))
ultima_bass.localkey_is_minor = ultima_bass.localkey_is_minor.map({False: 'in major', True: 'in minor'})
#ultima_bass.style.apply(highlight, axis=1)
fig = px.pie(ultima_bass, names='bass_note', values='counts',
             facet_row='cadence', facet_col='localkey_is_minor',
             height=1500,
             category_orders={'cadence': cadence_counts.index},
            )
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_traces(textposition='inside', textinfo='percent+label')
fig.update_layout(**STD_LAYOUT)
fig.show()

Chord progressions#

PACs with ultima I/i#

#pac_on_i = phrase_segments.groupby(level=[0,1,2], group_keys=False).apply(lambda df: df if ((df.cadence == 'PAC') & (df.numeral.isin(('I', 'i')))).any() else None)
#pac_on_i.cadence.value_counts()
#pac_on_i.droplevel(-1).index.nunique()
def get_progressions(selected='PAC', last_row={}, feature='chord', dataset=None, as_series=True):
    """Uses the nonlocal variable phrase_segments."""
    last_row = {k: v if isinstance(v, tuple) else (v,) for k, v in last_row.items()}
    progressions = []

    for (corp, fname, *_), df in phrase_segments[phrase_segments[feature].notna()].groupby(level=[0,1,2]):
        if dataset is not None and dataset not in corp:
            continue
        if (df.cadence == selected).fillna(False).any():
            # remove chords after the last cadence label
            df = df[df.cadence.fillna(method='bfill').notna()]
            # group segments leading up to a cadence label
            cadence_groups = df.cadence.notna().shift().fillna(False).cumsum()
            for i, cadence in df.groupby(cadence_groups):
                last_r = cadence.iloc[-1]
                typ = last_r.cadence
                if typ != selected:
                    continue
                if any(last_r[feat] not in values for feat, values in last_row.items()):
                    continue
                progressions.append(tuple(cadence[feature]))
    if as_series:
        return pd.Series(progressions)
    return progressions
chord_progressions = get_progressions('PAC', dict(numeral=('I', 'i')), 'chord')
print(f"Progressions for {len(chord_progressions)} cadences:")
value_count_df(chord_progressions, "chord progressions")
Progressions for 781 cadences:
counts
chord progressions
(I, V7/IV, IV, I, V(6), I, V7/IV, IV, I, V(6), I) 4
(V, IV, I, IV, I, V7, I, V, IV, I, IV, I, V7, I) 4
(I, I, #viio7, i, V7, i, bII6, V(64), V7, i) 3
(i(+6), V6(#4)/iv, ivM7, V6(#4)/III, IIIM7, bII6, V(964), V7(9), i(+6)) 3
(I, I(7), I, I(#2), I, I(#4), I, I(7), I, I(#2), I, I(#4), I, V43(b9+b5), I) 2
... ...
(I, vi6, V6, IV6, iii6, ii6, I6, IV6/IV, vi6, #viio6(2)/vi, #viio6/vi, i/vi) 1
(I, vi6, V6(2), V6, IV6(2), IV6, iii6(2), iii6, ii6(2), ii6, I6(2), I6, viio6(2), viio6, I) 1
(i, V6, i, viio64/iv, iv6, ii%7/iv, V7/iv, iv(4), iv, V65, i, VI6, v6(2), v6, iv6(2), iv6, V7, VI, ii%65, V, i) 1
(V, IV, V2, I6, I, V, iv, I6, vi6, ii7, V, I) 1
(V, vi7, V6, I, V43, V6, V, V2, vi64, I6, I6(#4), I6, V, vi7, V6, I, V43, V6, V, V2, vi64, I6, I6(#4), I6, V, viio/V, #viio64, i6, iio, V2/V, V6, V, i(94), V(#64), V(64), V, i, V, viio/V, #viio64, i6, iio, V2/V, V6, V, i(94), V(#64), V(64), V, i, V, i6, iio6(2), iio6, I64, I64(2), I64, #viio7/vi, #viio7(#2)/vi, #viio7/vi, vi, viio65(6)/V, viio65/V, bIII64, bIII64(4), bIII64, viio7, viio7(6), viio7, I, i, iio6, bII6, viio43, V, I) 1

735 rows × 1 columns

numeral_progressions = get_progressions('PAC', dict(numeral=('I', 'i')), 'numeral')
value_count_df(numeral_progressions, "numeral progressions")
counts
numeral progressions
(V, IV, I, IV, I, V, I, V, IV, I, IV, I, V, I) 4
(I, V, IV, I, V, I, V, IV, I, V, I) 4
(i, i, IV, IV, V, VI, ii, V, V, i) 3
(I, I, #vii, i, V, i, bII, V, V, i) 3
(i, V, iv, V, III, bII, V, V, i) 3
... ...
(I, vii, I, V, I, V, vi, I, I, IV, V, V, I) 1
(I, I, V, vi, I, V, I, V, I, V, vi, I, I, IV, V, V, I) 1
(I, vi, V, I, IV, IV, iii, iii, ii, ii, I, I, IV, V, V, I) 1
(V, I, IV, IV, iii, iii, ii, ii, I, I, IV, V, V, I) 1
(V, vi, V, I, V, V, V, V, vi, I, I, I, V, vi, V, I, V, V, V, V, vi, I, I, I, V, vii, #vii, i, ii, V, V, V, i, V, V, V, i, V, vii, #vii, i, ii, V, V, V, i, V, V, V, i, V, i, ii, ii, I, I, I, #vii, #vii, #vii, vi, vii, vii, bIII, bIII, bIII, vii, vii, vii, I, i, ii, bII, vii, V, I) 1

719 rows × 1 columns

def remove_immediate_duplicates(l):
    return tuple(a for a, b in zip(l, (None, ) + l) if a != b)

numeral_prog_no_dups = numeral_progressions.map(remove_immediate_duplicates)
value_count_df(numeral_prog_no_dups)
counts
(I, IV, V, I) 8
(i, iv, V, i) 5
(I, ii, V, I) 5
(i, ii, V, i) 4
(I, IV, V, vi, ii, V, I) 4
... ...
(V, I, IV, iii, ii, I, IV, V, I) 1
(I, V, vii, V, iii, ii, I, vii, vi, #vii, vi, IV, vii, iii, vi, ii, V, I, IV, vii, iii, vi, ii, V, I) 1
(V, iii, IV, ii, iii, I, ii, V, I) 1
(I, vii, I, V, I, IV, ii, V, vi, I, ii, V, I) 1
(V, vi, V, I, V, vi, I, V, vi, V, I, V, vi, I, V, vii, #vii, i, ii, V, i, V, i, V, vii, #vii, i, ii, V, i, V, i, V, i, ii, I, #vii, vi, vii, bIII, vii, I, i, ii, bII, vii, V, I) 1

684 rows × 1 columns

PACs ending on scale degree 1#

Scale degrees expressed w.r.t. major scale, regardless of actual key.

bass_progressions = get_progressions('PAC', dict(bass_note=0), 'bass_note')
bass_prog = bass_progressions.map(ms3.fifths2sd)
print(f"Progressions for {len(bass_progressions)} cadences:")
value_count_df(bass_prog, "bass progressions")
Progressions for 718 cadences:
counts
bass progressions
(5, 4, 1, 4, 1, 5, 1, 5, 4, 1, 4, 1, 5, 1) 4
(1, 1, 4, 1, 5, 1, 1, 4, 1, 5, 1) 4
(1, 1, 7, 1, 5, 1, 4, 5, 5, 1) 3
(3, 4, 5, 6, 3, 4, 5, 6, 3, 4, 5, 5, 1) 3
(1, 3, 4, 2, b3, 4, 5, 5, 1) 3
... ...
(3, 1, 5, 6, 3, 7, 1, 5, 3, 7, 1, 1, 3, 4, 5, 5, 1) 1
(5, 3, 6, 6, 5, 5, 4, 4, 3, 3, 4, 5, 5, 1) 1
(1, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 7, 7, 6, 4, 2, 3, 1, 2, 7, 1, 6, 7, 5, 6, 4, 5, 1) 1
(1, 5, 6, 4, 5, 3, 4, 5, 1) 1
(5, 6, 7, 1, 2, 7, 5, 4, 3, 3, 3, 3, 5, 6, 7, 1, 2, 7, 5, 4, 3, 3, 3, 3, 5, #4, 4, b3, 2, 1, 7, 5, 1, 5, 5, 5, 1, 5, #4, 4, b3, 2, 1, 7, 5, 1, 5, 5, 5, 1, 5, b3, 4, 4, 5, 5, 5, #5, #5, #5, 6, 6, 6, b7, b7, b7, 7, 7, 7, 1, 1, 4, 4, 4, 5, 1) 1

658 rows × 1 columns

bass_prog_no_dups = bass_prog.map(remove_immediate_duplicates)
value_count_df(bass_prog_no_dups)
counts
(1, 7, 6, 5, 4, 3, 4, 5, 1) 6
(1, 4, 5, 1) 5
(1, 4, 5, b6, 4, 5, 1) 4
(1, 4, 1, 5, 1, 4, 1, 5, 1) 4
(5, 4, 1, 4, 1, 5, 1, 5, 4, 1, 4, 1, 5, 1) 4
... ...
(3, 4, 5, 1, 6, 5, 1, 3, 6, 7, 1, b3, 4, 5, 1) 1
(6, 1, 4, 5, 6, 7, 1, 3, 4, 5, 6, 3, 4, 5, 1) 1
(6, 1, 6, 7, 1, 3, 4, 5, 6, 4, 5, 6, 3, 4, 5, 1, 3, 4, 6, 3, 4, 5, 1) 1
(1, 3, 1, 4, 1, 5, 6, 5, 1, 7, 1, b7, b6, 5, 1, 4, 5, b6, 4, 5, 1) 1
(5, 6, 7, 1, 2, 7, 5, 4, 3, 5, 6, 7, 1, 2, 7, 5, 4, 3, 5, #4, 4, b3, 2, 1, 7, 5, 1, 5, 1, 5, #4, 4, b3, 2, 1, 7, 5, 1, 5, 1, 5, b3, 4, 5, #5, 6, b7, 7, 1, 4, 5, 1) 1

623 rows × 1 columns

def make_sankey(data, labels, node_pos=None, margin={'l': 10, 'r': 10, 'b': 10, 't': 10}, pad=20, color='auto', **kwargs):
    if color=='auto':
        unique_labels = set(labels)
        color_step = 100 / len(unique_labels)
        unique_colors = {label: f'hsv({round(i*color_step)}%,100%,100%)' for i, label in enumerate(unique_labels)}
        color = list(map(lambda l: unique_colors[l], labels))
    fig = go.Figure(go.Sankey(
        arrangement = 'snap',
        node = dict(
          pad = pad,
          #thickness = 20,
          #line = dict(color = "black", width = 0.5),
          label = labels,
          x = [node_pos[i][0] if i in node_pos else 0 for i in range(len(labels))] if node_pos is not None else None,
          y = [node_pos[i][1] if i in node_pos else 0 for i in range(len(labels))] if node_pos is not None else None,
          color = color,
          ),
        link = dict(
          source = data.source,
          target = data.target,
          value = data.value
          ),
        ),
     )

    fig.update_layout(margin=margin, **kwargs)
    return fig

def progressions2graph_data(progressions, cut_at_stage=None):
    stage_nodes = defaultdict(dict)
    edge_weights = Counter()
    node_counter = 0
    for progression in progressions:
        previous_node = None
        for stage, current in enumerate(reversed(progression)):
            if cut_at_stage and stage > cut_at_stage:
                break
            if current in stage_nodes[stage]:
                current_node = stage_nodes[stage][current]
            else:
                stage_nodes[stage][current] = node_counter
                current_node = node_counter
                node_counter += 1
            if previous_node is not None:
                edge_weights.update([(current_node, previous_node)])
            previous_node = current_node
    return stage_nodes, edge_weights

def graph_data2sankey(stage_nodes, edge_weights):
    data = pd.DataFrame([(u, v, w) for (u, v), w in edge_weights.items()], columns = ['source', 'target', 'value'])
    node2label = {node: label for stage, nodes in stage_nodes.items() for label, node in nodes.items()}
    labels = [node2label[i] for i in range(len(node2label))]
    return make_sankey(data, labels)

def plot_progressions(progressions, cut_at_stage=None):
    stage_nodes, edge_weights = progressions2graph_data(progressions, cut_at_stage=cut_at_stage)
    return graph_data2sankey(stage_nodes, edge_weights)

plot_progressions(numeral_prog_no_dups, cut_at_stage=3)
chord_progressions_minor = get_progressions('PAC', dict(numeral='i', localkey_is_minor=True), 'root')
chord_progressions_minor
0               (0, -1, -1, 1, 0, -4, 2, -3, 0, 2, 1, 0)
1         (0, 3, 1, -1, -1, -3, -3, 2, 2, 1, 1, 1, 1, 0)
2      (1, -1, -1, 5, 0, 0, 0, -5, -5, 1, -4, -4, 0, ...
3      (0, -4, -2, -3, 0, -1, 1, 1, -1, -1, -1, 4, 0,...
4      (0, -1, 4, -1, 2, -4, 0, 0, 2, 1, 0, 0, 0, 2, ...
                             ...
362                    (0, 4, -1, 4, -1, 4, -1, 1, 1, 0)
363                    (0, 4, -1, 4, -1, 4, -1, 1, 1, 0)
364                    (0, 4, -1, 4, -1, 4, -1, 1, 1, 0)
365                      (0, 0, 5, 0, 1, 0, -5, 1, 1, 0)
366                            (1, 0, 5, -4, 1, 0, 5, 0)
Length: 367, dtype: object
pac_major = get_progressions('PAC', dict(numeral='I', localkey_is_minor=False), 'chord')
plot_progressions(pac_major, cut_at_stage=4)
deceptive = get_progressions('DC', dict(localkey_is_minor=False), 'chord')
deceptive.value_counts()
(I, ii2, I, I6, ii65, V(64), V, vi)                               1
(I, I, V, I, vi, V/vi, vi, IV, V/IV, IV, ii, V/ii, ii, V, vi7)    1
(I, V2, I6, IV, V6/V, V, V6/vi, i/vi, V(64)/vi, V/vi, VI/vi)      1
dtype: int64
plot_progressions(deceptive, cut_at_stage=4)
plot_progressions(bass_prog_no_dups, cut_at_stage=7)
def remove_sd_accidentals(t):
    return tuple(map(lambda sd: sd[-1], t))

bass_prog_no_acc_no_dup = bass_prog.map(remove_sd_accidentals).map(remove_immediate_duplicates)
plot_progressions(bass_prog_no_acc_no_dup, cut_at_stage=7)

HCs ending on V#

half = get_progressions('HC', dict(numeral='V'), 'bass_note').map(ms3.fifths2sd)
print(f"Progressions for {len(half)} cadences:")
plot_progressions(half.map(remove_immediate_duplicates), cut_at_stage=5)
Progressions for 250 cadences: